<?php

namespace App\Console\Commands;

use App\Libs\Xlsx\XlsWriter;
use Exception;
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\PromptsForMissingInput;
use Illuminate\Support\Facades\DB;

class EpsImport extends Command implements PromptsForMissingInput
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'app:eps-import {path}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'import data of enterprise data from aqc';

    /**
     * 总文件数量
     * @var int
     * create_at: 2025-09-06 10:53:17
     * update_at: 2025-09-06 10:53:17
     */
    protected $totalNumber = 0;

    /**
     * 总数据数量
     * @var int
     * create_at: 2025-09-06 13:53:05
     * update_at: 2025-09-06 13:53:05
     */
    protected $totalRows = 0;

    /**
     * 当前第N个
     * @var int
     * create_at: 2025-09-06 10:55:34
     * update_at: 2025-09-06 10:55:34
     */
    protected $currentNumber = 0;

    /**
     * 当前文件
     * @var string
     * create_at: 2025-09-06 10:53:26
     * update_at: 2025-09-06 10:53:26
     */
    protected $currentFile = '';

    /**
     * Execute the console command.
     */
    public function handle()
    {
        // 路径
        $path = $this->argument('path');
        $path = str_replace('\\', '/', $path);

        // 目标文件
        $targets = [];

        // 路径 or 具体的文件
        if (is_dir($path)) {
            $this->info("输入的是一个目录...");
            // 获取目录及子目录下的所有 xlsx 文件
            $targets = array_merge($targets, $this->scanXlsx($path));
        } else {
            $this->info("输入的是一个具体的文件...");
            $targets[] = [
                'filepath' => $path,
                'count' => 0,
            ];
        }

        $this->totalRows = DB::table('eps')->count();

        $this->totalNumber = $total = count($targets);
        $this->warn("共计 {$total} 个文件待处理...");
        $this->newLine();

        $this->info("🚀 开始处理...");
        $this->newLine(2);

        $bar = $this->output->createProgressBar($total);
        $bar->setBarWidth(150);
        $bar->maxSecondsBetweenRedraws(0.5);

        $bar->setFormat(
            "<fg=green>%message%</>\n" .
            "<fg=blue>进度:</> <fg=cyan>%current%</>/<fg=cyan>%max%</> " .
            "<fg=yellow>[%bar%]</> " .
            "<fg=magenta>%percent:3s%%</>"
        );
        // 设置进度条填充字符和颜色
        $bar->setBarCharacter('<fg=green>●</>');
        $bar->setEmptyBarCharacter('<fg=gray>○</>');
        $bar->setProgressCharacter('<fg=blue>▶</>');

        // 初始消息
        $bar->setMessage("<fg=white;options=bold>准备就绪，开始处理...</>");

        // 进度条开始
        $bar->start();

        try {
            $i = 0;
            foreach ($targets as &$target) {
                // 当前文件
                $this->currentFile = $target['filepath'];

                // 处理文件
                $this->handleFileImport($bar, $target);
                // 手动前进进度条
                $bar->advance();
                $this->currentNumber = $i + 1;

                // 删除目标文件
                unlink($target['filepath']);

                $i++;
            }
        } catch (Exception $e) {
            $this->newLine(2);
            $this->error($e->getMessage());
            exit();
        }

        // 进度条结束
        $bar->setMessage("<fg=green;options=bold>✅ 数据导入完成！</>");
        $bar->finish();

        $this->newLine(2);

        $res = [];
        foreach ($targets as $k => $v) {
            $res[] = [$k, $v['filepath'], $v['count']];
        }

        // 结果
        $this->line("<fg=white;bg=green>📊 处理统计</>");
        $this->newLine();
        $this->table(["序号", "文件", "统计"], $res);
    }

    /**
     * 扫描目录及子目录下的所有 xlsx 文件
     * @param $path
     * @param $targets
     * create_at: 2025-09-05 15:19:41
     * update_at: 2025-09-05 15:19:41
     */
    protected function scanXlsx($path)
    {
        $targets = [];

        $objs = scandir($path);
        foreach ($objs as $obj) {
            if ($obj == '.' || $obj == '..') {
                continue;
            }

            if (is_file($path . '/' . $obj) && strtolower(pathinfo($obj, PATHINFO_EXTENSION)) == 'xlsx') {
                $targets[] = [
                    'filepath' => $path . '/' . $obj,
                    'count' => 0,
                ];
            }
            if (is_dir($path . '/' . $obj)) {
                $targets = array_merge($targets, $this->scanXlsx($path . '/' . $obj, $targets));
            }
        }

        return $targets;
    }

    /**
     * 文件导入（single）
     * @param $target
     * @throws Exception
     * create_at: 2025-09-06 08:54:00
     * update_at: 2025-09-06 08:54:00
     */
    protected function handleFileImport(&$bar, &$target)
    {
        $_importDataType = [];

        // 字段
        $fields = [
            "ent_name",
            "ent_status",
            "ent_legal_person",
            "reg_capital",
            "paid_in_capital",
            "establish_date",
            "approval_date",
            "business_term",
            "province",
            "city",
            "district",
            "tel",
            "more_tel",
            "email",
            "more_email",
            "unified_social_credit_code",
            "tax_identification_number",
            "registration_number",
            "organization_code",
            "insured_number",
            "ent_type",
            "industry",
            "ent_former_name",
            "registered_address",
            "latest_annual_report_address",
            "website",
            "business_scope",
            "created_at",
            "updated_at"
        ];

        // closures
        $closures = [
            "tel" => function ($v) {
                return mb_strlen($v) > 512 ?
                    mb_substr(mb_substr($v, 0, 512), 0, strrpos(mb_substr($v, 0, 512), ",")) :
                    $v;
            },
            "more_tel" => function ($v) {
                return mb_strlen($v) > 512 ?
                    mb_substr(mb_substr($v, 0, 512), 0, strrpos(mb_substr($v, 0, 512), ",")) :
                    $v;
            },
            "email" => function ($v) {
                return mb_strlen($v) > 512 ?
                    mb_substr(mb_substr($v, 0, 512), 0, strrpos(mb_substr($v, 0, 512), ",")) :
                    $v;
            },
            "more_email" => function ($v) {
                return mb_strlen($v) > 512 ?
                    mb_substr(mb_substr($v, 0, 512), 0, strrpos(mb_substr($v, 0, 512), ",")) :
                    $v;
            },
        ];

        $conf = ['path' => str_replace('\\', '/', dirname($target['filepath']))];
        $cls = new XlsWriter($conf);

        // 读取测试文件
        $cls->openFile(basename($target['filepath']));
        $cls->openSheet();

        try {
            $i = 0;
            $data = [];
            $cur = date("Y-m-d H:i:s");
            while (($row = $cls->nextRow($_importDataType)) !== NULL) {
                // 更新进度条
                $message = "进度： {$this->currentNumber}/{$this->totalNumber}：<fg=blue>读取文件</> - 正在读取 " . $i + 1 . " 行";
                $bar->setMessage($message);
                $bar->display();

                if (0 == $i) {
                    if (count($row) != count($fields) - 2) {
                        break;
                    }
                    // 第一行是标题
                    $i++;
                    continue;
                }

                if (isAllEmpty($row)) {
                    // 空行
                    break;
                }

                // trim
                $row = array_map(function ($v) {
                    return trim($v);
                }, $row);

                $row[] = $cur;
                $row[] = $cur;

                $data[] = array_combine($fields, $row);

                $i++;
            }

        } catch (Exception $exception) {
            throw new Exception($exception->getMessage());
        } finally {
            // 手动销毁
            $cls->close();
        }

        // 数据处理
        if (!empty($closures)) {
            $rowkey = 0;
            $fileTotalRows = count($data);
            foreach ($data as $k => $row) {

                // 更新进度条
                $message = "进度：  {$this->currentNumber}/{$this->totalNumber}：<fg=cyan>处理文件数据</> - 正在处理 " . $rowkey + 1 . "/{$fileTotalRows} 行";
                $bar->setMessage($message);
                $bar->display();

                foreach ($closures as $k1 => $closure) {
                    if (isset($row[$k1])) {
                        $data[$k][$k1] = $closure($row[$k1]);
                    }
                }
                $rowkey++;
            }
        }

        // 导入数据
        try {
            DB::transaction(function () use ($bar, $data) {
                $this->importMain($bar, $data);
            });
        } catch (Exception $e) {
            throw new Exception($e->getMessage());
        }

        // 统计文件数据数量
        $target['count'] = count($data);
    }

    /**
     * 入库
     * @param $data
     * @return true
     * create_at: 2025-09-06 08:54:47
     * update_at: 2025-09-06 08:54:47
     */
    private function importMain(&$bar, $data)
    {
        if (empty($data)) {
            return true;
        }

        // 写入数据库
        $total = count($data);
        $handled = 0;
        $data = collect($data);
        $batchSize = 1000;
        foreach ($data->chunk($batchSize) as $chunk) {
            DB::table('eps')->insert($chunk->all());

            $chunkNum = $chunk->count();
            $handled += $chunkNum;

            // 更新进度条
            $this->totalRows += $chunkNum;

            $message = "进度：  {$this->currentNumber}/{$this->totalNumber}：<fg=green>转存文件数据</> - 已入库 " . $handled . "/{$total} 行 | 总入库 " . $this->totalRows . " 行";
            $bar->setMessage($message);
            $bar->display();
        }

        return true;
    }
}
